package com.cgwx.tmservice.controller;


import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cgwx.commonutils.result.Result;
import com.cgwx.springsecurity.annotation.Log;
import com.cgwx.springsecurity.enums.BusinessType;
import com.cgwx.tmservice.config.CanPortConfig;
import com.cgwx.tmservice.config.SPortConfig;
import com.cgwx.tmservice.entity.bean.LatestTmDisplayMatrix;
import com.cgwx.tmservice.entity.bean.TmBeanStatic;
import com.cgwx.tmservice.entity.bean.TmFrameConfigIdToIdentified;
import com.cgwx.tmservice.entity.tm.TmFrameConfig;
import com.cgwx.tmservice.entity.tm.TmInfoHisDate;
import com.cgwx.tmservice.entity.tm.TmInfoLogDate;
import com.cgwx.tmservice.entity.tm.TmParametersConfig;
import com.cgwx.tmservice.entity.vo.*;
import com.cgwx.tmservice.netty.UdpReceiveInitApplication;
import com.cgwx.tmservice.service.TmFrameConfigService;
import com.cgwx.tmservice.service.TmInfoHisDateService;
import com.cgwx.tmservice.service.TmInfoLogDateService;
import com.cgwx.tmservice.service.TmParametersConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 遥测前端控制器
 * </p>
 *
 * @author GaoWei
 * @since 2023-08-05
 */

@Api(tags = "遥测前端控制器")
@RestController
@RequestMapping("/tmservice/tm")
@CrossOrigin
public class TmController {

    @Autowired
    private TmFrameConfigService tmFrameConfigService;
    @Autowired
    private TmParametersConfigService tmParametersConfigService;
    @Autowired
    private UdpReceiveInitApplication udpReceiveInitApplication;
    @Autowired
    private TmInfoLogDateService tmInfoLogDateService;
    @Autowired
    private TmInfoHisDateService tmInfoHisDateService;
    @Autowired
    private CanPortConfig canPortConfig;
    @Autowired
    private SPortConfig sPortConfig;

    @Log(title = "上传遥测参数配置", businessType = BusinessType.TM_CONFIG_UPLOAD)
    @ApiOperation(value = "上传遥测配置表格")
    @PostMapping("updateTmConfig")
    public Result updateTmFrameConfig(
            @ApiParam(name = "file", value = "待上传的遥测配置表格") MultipartFile file){
//        判断上传文件是否为空
        if(file.getOriginalFilename() != null)
        {
            tmFrameConfigService.updateTmFrameConfig(file);
            tmParametersConfigService.updateTmParametersConfig(file,tmParametersConfigService);

//            更新遥测配置全局变量
            udpReceiveInitApplication.tmConfigInit();

            return Result.ok().data("message", "遥测配置表格上传成功");
        }else {
            return Result.error().data("message", "遥测配置表格上传失败");
        }
    }

    @ApiOperation(value = "查询遥测配置")
    @GetMapping("getAllTmConfig")
    public Result getAllTmConfig(){
//        创建用于封装最终展示数据的实体类
        List<TmFrameDisplayVo> tmList = new ArrayList<>();
//        遍历所有遥测帧，并在遍历时封装进此帧下的所有遥测参数
//        首先查询所有遥测帧
        List<TmFrameConfig> tmFrameConfigList = tmFrameConfigService.list(null);
//        遍历遥测帧，封装进最终展示数据的实体类
        for (TmFrameConfig tmFrameConfig : tmFrameConfigList) {
//            准备封装的一级节点，遥测帧名称及其下所有遥测参数集合
            TmFrameDisplayVo tmFrameDisplayVo = new TmFrameDisplayVo();
//            封装遥测帧名称
            tmFrameDisplayVo.setDisplayTitle(tmFrameConfig.getTmframeName().substring(0,tmFrameConfig.getTmframeName().indexOf(".xlsx")));
            tmFrameDisplayVo.setId(tmFrameConfig.getId());
//            创建二级节点，用于封装当前遥测帧下的所有遥测参数
            List<TmParamDisplayVo> tmParamDisplayVoList = new ArrayList<>();
//            得到当前遍历的遥测帧名称，作为条件遍历遥测参数表，查询出所有属于此帧的遥测参数
            String tmframeIdentifiers = tmFrameConfig.getTmframeIdentifiers();
            QueryWrapper<TmParametersConfig> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("tmframe_identifiers",tmframeIdentifiers);
            List<TmParametersConfig> tmParametersConfigList = tmParametersConfigService.list(queryWrapper);
//            封装全部二级节点
            for (TmParametersConfig tmParametersConfig : tmParametersConfigList) {
                TmParamDisplayVo tmParamDisplayVo = new TmParamDisplayVo();
                String displayTitle = tmParametersConfig.getTmCode() + ' ' + tmParametersConfig.getTmName();
                tmParamDisplayVo.setDisplayTitle(displayTitle);
                tmParamDisplayVo.setId(tmParametersConfig.getId());
                tmParamDisplayVoList.add(tmParamDisplayVo);
            }
//            将二级节点封装进一级节点
            tmFrameDisplayVo.setDisplayChildren(tmParamDisplayVoList);
//            将封装好的一级节点封装进最终展示数据
            tmList.add(tmFrameDisplayVo);
        }
        return Result.ok().data("tmList",tmList);
    }

    @ApiOperation(value = "根据ID查询遥测参数配置")
    @GetMapping("getTmParamConfigById/{id}")
    public Result getTmParamConfigById(
            @ApiParam(name = "id", value = "待查询的遥测参数配置id")
            @PathVariable String id){
        if(TmFrameConfigIdToIdentified.TM_FRAME_ID_IDENTIFIED.get(id) != null){
//            说明前端选中的是遥测帧的id
            return Result.ok();
        }else{
//            说明前端选中的是遥测参数的id
            TmParametersConfig tmParametersConfig = tmParametersConfigService.getById(id);
            return Result.ok().data("tmParamConfig", tmParametersConfig);
        }
    }

    @ApiOperation(value = "查询最新的一帧遥测")
    @GetMapping("getRealTimeTmFrame")
    public Result getRealTimeTmFrame(){
//        在当日遥测原码表中查找最新一条遥测原码数据
        return Result.ok().data("realTimeTmFrame", TmBeanStatic.TM_FRAME_LOG_REALTIME);
    }

    @ApiOperation(value = "根据用户选择遥测帧，查询当前最新的遥测帧结果,table显示")
    @GetMapping("getTmListById/{id}")
    public Result getTmListById(
            @ApiParam(name = "id", value = "待查询的遥测参数帧id，此id为遥测帧配置表（tm_frame_config） id")
            @PathVariable String id){
//        根据id得到identifiers
        String tmframe_identifiers = TmFrameConfigIdToIdentified.TM_FRAME_ID_IDENTIFIED.get(id);
//        根据identifiers得到当前最新的遥测解析矩阵
        ArrayList<TmInfoHisDate> tmInfoHisDateArrayList = LatestTmDisplayMatrix.LATEST_TM_DISPLAY_MATRIX.get(tmframe_identifiers);
//        在当日遥测原码表中查找最新一条遥测原码数据
        return Result.ok().data("tmInfoHisDateArrayList", tmInfoHisDateArrayList);
    }

    @ApiOperation(value = "根据ID判断是遥测帧还是遥测参数")
    @GetMapping("queryIsFrameOrParamById/{id}")
    public Result queryIsFrameOrParamById(
            @ApiParam(name = "id", value = "待查询id")
            @PathVariable String id){
        if(TmFrameConfigIdToIdentified.TM_FRAME_ID_IDENTIFIED.get(id) != null){
//            说明前端选中的是遥测帧的id
            return Result.ok().data("id", "frame");
        }else{
//            说明前端选中的是遥测参数的id
            return Result.ok().data("id", "param");
        }
    }

    @ApiOperation(value = "根据ID集合判断是否包含遥测帧")
    @PostMapping("queryIsContainFrameByIdList")
    public Result queryIsContainFrameByIdList(
            @ApiParam(name = "idList", value = "待查询的id集合")
            @RequestBody List<String> idList){
        List<String> checkedTmFrameIdList = new ArrayList<>();
        for (String id : idList) {
            if(TmFrameConfigIdToIdentified.TM_FRAME_ID_IDENTIFIED.get(id) != null){
//            说明此id为遥测帧id
                checkedTmFrameIdList.add(id);
            }
        }
        return Result.ok().data("checkedTmFrameIdList",checkedTmFrameIdList);
    }

    @Log(title = "删除遥测参数配置", businessType = BusinessType.TM_CONFIG_DELETE)
    @ApiOperation(value = "根据遥测帧配置ID，删除遥测帧配置和对应的遥测参数配置")
    @GetMapping("deleteTmFrameById/{id}")
    public Result deleteTmFrameById(
            @ApiParam(name = "id", value = "待删除的遥测帧配置id")
            @PathVariable String id){
//        是否为遥测帧id的判断在前端实现，此处传递过来的确定为遥测帧配置ID
//        删除遥测帧配置表中的配置信息
        boolean removeTmFrame = tmFrameConfigService.removeById(id);
//        根据id查询遥测识别码
        String identifiers = TmFrameConfigIdToIdentified.TM_FRAME_ID_IDENTIFIED.get(id);
        QueryWrapper<TmParametersConfig> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tmframe_identifiers",identifiers);
//        删除遥测参数配置表中的配置信息
        boolean removeTmParam = tmParametersConfigService.remove(queryWrapper);

//        更新全局变量配置信息
        udpReceiveInitApplication.tmConfigInit();

        if(removeTmFrame & removeTmParam){
//            两表都删除成功
            return Result.ok().data("message", "遥测帧删除成功");
        }else{
            return Result.error().data("message", "遥测帧删除失败");
        }
    }

    @Log(title = "遥测解析表导出", businessType = BusinessType.TM_CONFIG_EXPORT)
    @ApiOperation(value = "根据用户选择的参数，查询遥测解析记录并返回")
    @PostMapping("getTmHisReplayList")
    public void getTmHisReplayList(
            @ApiParam(name = "tmReplayDataVo", value = "待回放的遥测信息")
            @RequestBody TmReplayDataVo tmReplayDataVo,
            HttpServletResponse response) throws IOException {
//        设置下载信息
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
//        这里URLEncoder.encode可以防止中文乱码 当然和easyExcel没有关系
        String fileName = URLEncoder.encode("遥测解析下载", StandardCharsets.UTF_8);
        response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
//        创建用于封装对象的Excel实体类集合
        List<TmParamExcelDownloadVo> tmParamExcelDownloadVoList = new ArrayList<>();
//        查询数据
        List<TmInfoHisDate> tmHisReplayList = tmInfoHisDateService.getTmHisReplayList(tmReplayDataVo);
//        添加数据到tmParamExcelDownload列表
        for (TmInfoHisDate tmInfoHisDate : tmHisReplayList) {
            TmParamExcelDownloadVo tmParamExcelDownloadVo = new TmParamExcelDownloadVo();
            BeanUtils.copyProperties(tmInfoHisDate,tmParamExcelDownloadVo);
            tmParamExcelDownloadVoList.add(tmParamExcelDownloadVo);
        }
//        写入Excel
        EasyExcel.write(response.getOutputStream(), TmParamExcelDownloadVo.class).sheet("遥测解析记录").doWrite(tmParamExcelDownloadVoList);
    }

    @Log(title = "遥测原码表导出", businessType = BusinessType.TM_CONFIG_EXPORT)
    @ApiOperation(value = "根据用户选择的参数，查询遥测原码记录并返回")
    @PostMapping("getTmLogReplayList")
    public void getTmLogReplayList(
            @ApiParam(name = "tmReplayDataVo", value = "待回放的遥测信息")
            @RequestBody TmReplayDataVo tmReplayDataVo,
            HttpServletResponse response) throws IOException {
//        设置下载信息
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
//        这里URLEncoder.encode可以防止中文乱码 当然和easyExcel没有关系
        String fileName = URLEncoder.encode("遥测原码下载", StandardCharsets.UTF_8);
        response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
//        创建用于封装对象的Excel实体类集合
        List<TmFrameExcelDownloadVo> tmFrameExcelDownloadVoList = new ArrayList<>();
//        查询数据
        List<TmInfoLogDate> tmLogReplayList = tmInfoLogDateService.getTmLogReplayList(tmReplayDataVo);
//        添加数据到tmParamExcelDownload列表
        for (TmInfoLogDate tmInfoLogDate : tmLogReplayList) {
            TmFrameExcelDownloadVo tmFrameExcelDownloadVo = new TmFrameExcelDownloadVo();
            BeanUtils.copyProperties(tmInfoLogDate,tmFrameExcelDownloadVo);
            tmFrameExcelDownloadVoList.add(tmFrameExcelDownloadVo);
        }
//        写入Excel
        EasyExcel.write(response.getOutputStream(), TmFrameExcelDownloadVo.class).sheet("遥测原码记录").doWrite(tmFrameExcelDownloadVoList);
    }

    @ApiOperation(value = "查询上行设备信息")
    @GetMapping("getTmInstrumentInfo")
    public Result getTmInstrumentInfo(){
        Map<String,String> TmInstrumentInfo = new HashMap<>();
        TmInstrumentInfo.put("canReceivePort",canPortConfig.getListeningPort().toString());
        TmInstrumentInfo.put("sReceivePort",sPortConfig.getListeningPort().toString());
//        todo
        TmInstrumentInfo.put("xReceivePort","not configured yet");
//        返回数据
        return Result.ok().data("TmInstrumentInfo",TmInstrumentInfo);
    }
}

